package com.bcx.wind.workflow.core.flow.node;

import com.bcx.wind.workflow.access.QueryFilter;
import com.bcx.wind.workflow.core.constant.NodeType;
import com.bcx.wind.workflow.core.constant.TaskType;
import com.bcx.wind.workflow.core.constant.WorkflowOperate;
import com.bcx.wind.workflow.core.flow.NodeModel;
import com.bcx.wind.workflow.core.flow.TaskNodeModel;
import com.bcx.wind.workflow.core.flow.handler.DefaultHandler;
import com.bcx.wind.workflow.core.flow.handler.ExecuteHandler;
import com.bcx.wind.workflow.core.flow.handler.JointlyHandler;
import com.bcx.wind.workflow.core.flow.handler.StrandHandler;
import com.bcx.wind.workflow.entity.WindActHistory;
import com.bcx.wind.workflow.entity.WindTask;
import com.bcx.wind.workflow.handler.TaskHandler;
import com.bcx.wind.workflow.pojo.Task;
import com.bcx.wind.workflow.pojo.WindConfig;
import com.bcx.wind.workflow.pojo.WindUser;
import com.bcx.wind.workflow.support.*;

import java.util.*;
import java.util.stream.Collectors;

import static com.bcx.wind.workflow.core.constant.NodeConfigConstant.*;
import static com.bcx.wind.workflow.core.constant.OrderVariableConstant.*;
import static com.bcx.wind.workflow.message.ErrorCode.RETURN_NODE_NOT_FOUND;
import static com.bcx.wind.workflow.message.ErrorCode.SUBMIT_NODE_NOT_FOUND;
import static com.bcx.wind.workflow.message.ErrorCode.TASK_NODE_REJECT_ERROR;

/**
 * <p>
 *
 *   任务节点
 * </p>
 *
 * @author zhanglei
 */
public class TaskNode extends BaseNode implements TaskNodeModel {

    /**
     * 是否会签
     */
    private boolean jointly;

    /**
     * 是否串签
     */
    private boolean strand;

    /**
     * 是否在分支和聚合中
     */
    private boolean inForkJoin;

    /**
     * 是否拦截
     */
    private boolean interceptor;

    /**
     * 是否在并且分支中
     */
    private boolean inAnd;


    /**
     * 是否在或者分支中
     */
    private boolean inOr;


    /**
     * 是否在动态分支中   动态分支默认为并且状态
     */
    private boolean inDyna;


    /**
     * 是否是第一个任务
     */
    private boolean isFirstTask;

    /**
     * 是否是在最后一个任务
     */
    private boolean isLastTask;

    /**
     * 审核人
     */
    private List<WindUser>  approveUsers;


    public TaskNode(String nodeId, String nodeName) {
        super(nodeId, nodeName);
        this.nodeType = NodeType.TASK;
    }


    @Override
    public void executor() {
        //完成当前任务
        complete();

        //执行后续
        if(this.wind().isNext()){
            //删除流程中针对当前节点保存的变量数据
            removeOrderNodeVariable();

            //删除当前任务的子任务
            removeChildTask();

            //如果为退回操作，则直接退回到指定节点
            if(wind().getOperate() == WorkflowOperate.reject){
                submitNode();
                return;
            }

            //如果提交指定节点不为空，则直接提交到指定节点
            if(this.wind().getSubmitNode() != null){
                submitNode();
                return;
            }

            //执行下一步
            next(null);
        }

        //如果是串签，则新建新的任务
        if (this.strand() && !ObjectHelper.isEmpty(wind().getApproveUsers())) {
            handler(new TaskHandler(this.commandContext(),this,this.task()));
        }

    }

    private void removeChildTask(){
        String taskId = task().getWindTask().getId();
        QueryFilter filter = new QueryFilter()
                .setParentId(taskId);
        List<WindTask> windTasks = commandContext().access().selectTaskInstanceList(filter);
        if(!ObjectHelper.isEmpty(windTasks)){
            //删除任务
            commandContext().access().removeTaskInstanceByParentId(taskId);

            //删除子任务操作人
            List<String> taskIds = windTasks.stream().map(WindTask::getId).collect(Collectors.toList());
            commandContext().access().removeTaskActorByTaskIds(taskIds);
        }
    }

    /**
     * 指定提交
     */
    private void submitNode(){
        String submitNode = this.wind().getSubmitNode();
        NodeModel taskModel =  wind().getWindProcess().processModel().getTaskModel(submitNode);
        Assert.notEmptyError(SUBMIT_NODE_NOT_FOUND,taskModel,submitNode);
        Assert.isTrueError(SUBMIT_NODE_NOT_FOUND,taskModel instanceof ScribeTaskNode || taskModel instanceof Custom,submitNode);
        Assert.isTrueError(SUBMIT_NODE_NOT_FOUND,taskModel instanceof TaskNode && ((TaskNode) taskModel).inForkJoin,submitNode);
        if(this.inRouter() && !taskModel.inRouter()){
            //删除子流程实例
            this.commandContext().access().removeOrderInstanceByParentId(this.wind().getWindOrder().getId());
        }
        handler(new TaskHandler(this.commandContext(),taskModel,this.task()));
    }


    /**
     * 完成任务
     */
    private void complete(){
        //会签
        if(this.jointly()){
            executeHandler(new JointlyHandler(this.commandContext(),this.task()));
        }
        //串签
        else if(this.strand()){
            executeHandler(new StrandHandler(this.commandContext(),this.task()));
        }
        //普通
        else{
            executeHandler(new DefaultHandler(this.commandContext(),this.task()));
        }
        //判断是否可以执行后续
        canNext();

        //完成任务
        completeTaskOperate();
    }


    /**
     * 执行 针对于任务类型
     * @param handler  handler
     */
    private void  executeHandler(ExecuteHandler handler){
        handler.execute();
    }


    /**
     * 校验是否可以往后面执行
     */
    @SuppressWarnings("unchecked")
    private void  canNext(){
        //针对当前节点，除去当前操作的任务，其他的任务
        List<WindTask> windTasks = this.wind().getAllTasks();
        List<WindTask> tasks =  windTasks.stream().filter(wt->wt.getTaskName().equals(task().getNodeId())
                && !wt.getId().equals(task().getWindTask().getId()))
                .collect(Collectors.toList());

        //流程配置中的审批数量
        Object  approveMinCount = getOrderValue(JOINTLY_MIN_COUNT);
        //流程配置中的
        if(approveMinCount != null){
            Map<String,Object> variable = JsonHelper.objectToMap(approveMinCount);
            Object nodeApproveMinCount = variable.get(task().getNodeId());

            if(nodeApproveMinCount != null) {
                Map<String,Object> nodeVariable = JsonHelper.objectToMap(nodeApproveMinCount);
                Object successCount = nodeVariable.get(JOINTLY_SUCCESS_COUNT);
                Object nowCount = nodeVariable.get(JOINTLY_NOW_COUNT);

                //判断是否可以向下执行
                if (successCount != null && nowCount != null) {
                    int success = Integer.parseInt(successCount.toString());
                    int now = Integer.parseInt(nowCount.toString());
                    this.wind().setNext(success <= now);
                    //如果是串签，则移动一位

                    if(this.strand()){
                        this.wind().setNext(success < now);
                    }

                    //如果不可以执行到下一步，并且当前节点的任务已经为空了,并且不是串签，则表示该会签中有部分人执行了退回，所以需要将当前工作流操作改成退回
                    if(!this.wind().isNext() && tasks.isEmpty() && !this.strand()){
                        this.wind().setOperate(WorkflowOperate.reject);
                        this.wind().setSubmitNode(getReturnNode());
                        this.wind().setNext(true);
                    }


                    if(this.wind().isNext()) {
                        //存在多余的任务，需要手动删除
                        deleteSurpTask(tasks);
                    }

                    return;
                }
            }
        }

        if(tasks.isEmpty()){
            this.wind().setNext(true);
            //存在多余的任务，需要手动删除
            deleteSurpTask(tasks);
            return;
        }

        this.wind().setNext(false);
    }


    private String getReturnNode(){
        String returnNode = null;
        //最先考虑参数中的退回节点
        if(wind().getSubmitNode() !=null){
            returnNode =  wind().getSubmitNode();
        }

        //如果参数中的退回节点为空，则考虑配置中的
        if(returnNode == null) {
            Object returnNodeObj = task().getConfig().nodeConfig().get(RETURN_NODE);
            returnNode = returnNodeObj == null ? null : returnNodeObj.toString();
        }

        //如果没有配置则退回到初始节点
        if(returnNode == null){
            returnNode =  wind().getWindProcess().processModel().getFirstTaskNode().nodeId();
        }

        //如果还为空则报错
        Assert.notEmptyError(RETURN_NODE_NOT_FOUND,returnNode);

        //校验退回节点是否可以退回
        List<Task> rejectNodes = wind().getCurNode().get(0).getCanRejectTasks();
        List<String> nodeIds = rejectNodes.stream().map(Task::getNodeId).collect(Collectors.toList());
        Assert.isTrueError(TASK_NODE_REJECT_ERROR,Collections.frequency(nodeIds,returnNode) == 0,returnNode);
        return returnNode;
    }

    private String  returnNode(List<NodeModel> nodeModels){
        for(NodeModel nodeModel : nodeModels){
            List<NodeModel> nodes = nodeModel.preTask();
            if(nodes.size() == 1){
                return nodes.get(0).nodeId();
            }
            return returnNode(nodes);
        }
        return null;
    }

    /**
     * 删除多余的任务
     *
     * @param tasks  多余的任务集合
     */
    private void deleteSurpTask(List<WindTask> tasks){
        for(WindTask task : tasks){
            //删除任务
            this.commandContext().access().removeTaskInstanceById(task.getId());
            //删除审批人
            this.commandContext().access().removeTaskActorByTaskId(task.getId());
        }
    }


    /**
     * 完成任务的操作
     */
    private void  completeTaskOperate(){
        //删除任务
        this.commandContext().access().removeTaskInstanceById(task().getWindTask().getId());
        //删除审批人
        this.commandContext().access().removeTaskActorByTaskId(task().getWindTask().getId());
        //更新历史履历
        changeActHistory();
    }

    private  void  removeOrderNodeVariable(){
        //删除流程变量中的相关会签串签数据
        Map<String,Object> variable = this.wind().getWindOrder().variable();
        ObjectHelper.removeVariable(variable, JOINTLY_MIN_COUNT, this.task().getNodeId());
        this.wind().getWindOrder().setVariable(JsonHelper.toJson(variable));
    }


    /**
     * 更新流程执行履历
     */
    private  void  changeActHistory(){
        String taskId = task().getWindTask().getId();
        QueryFilter filter = new QueryFilter()
                .setTaskId(taskId);
        List<WindActHistory> actHistories = commandContext().access().selectActiveHistoryList(filter);
        if (!ObjectHelper.isEmpty(actHistories)) {
            WindActHistory actHistory = actHistories.get(0);
            actHistory.setOperate(wind().getOperate().name())
                    .setSuggest(wind().getSuggest())
                    .setApproveTime(TimeHelper.nowDate())
                    .setActorId(user().proxyUserId())
                    .setActorName(user().proxyUserName())
                    .setSubmitUserVariable(JsonHelper.toJson(user()));
            //更新履历
            commandContext().access().updateActiveHistory(actHistory);
        }
    }


    /**
     * 当前任务配置中的任务类型配置
     * @param config  任务配置
     * @return         任务类型
     */
    private String  taskTypeConfig(WindConfig config){
        Object type =  config.nodeConfig().get(TASK_TYPE);
        if(type != null){
            String taskType =  type.toString();
            if(TaskType.taskType(taskType) != null){
                return taskType;
            }
        }
        return null;
    }


    @Override
    public boolean jointly() {
        if(this.task() != null && this.task().getConfig() != null){
            String taskType = taskTypeConfig(this.task().getConfig());
            return taskType == null ? this.jointly : taskType.equals(TaskType.jointly.name());
        }
        return this.jointly;
    }

    @Override
    public boolean strand() {
        if(this.task() != null && this.task().getConfig() != null){
            String taskType = taskTypeConfig(this.task().getConfig());
            return taskType == null ? this.strand : taskType.equals(TaskType.strand.name());
        }
        return this.strand;
    }

    @Override
    public boolean inForkJoin() {
        return this.inForkJoin;
    }

    @Override
    public boolean inAnd() {
        return this.inAnd;
    }

    @Override
    public boolean inOr() {
        return this.inOr;
    }

    @Override
    public boolean inDyna() {
        return this.inDyna;
    }

    @Override
    public boolean isFirstTask() {
        return this.isFirstTask;
    }

    @Override
    public boolean isLastTask() {
        return this.isLastTask;
    }



    public void setJointly(boolean jointly) {
        this.jointly = jointly;
    }

    public void setStrand(boolean strand) {
        this.strand = strand;
    }

    public void setInForkJoin(boolean inForkJoin) {
        this.inForkJoin = inForkJoin;
    }

    public void setFirstTask(boolean firstTask) {
        isFirstTask = firstTask;
    }

    public void setLastTask(boolean lastTask) {
        isLastTask = lastTask;
    }

    public List<WindUser> getApproveUsers() {
        return approveUsers;
    }

    public void setApproveUsers(List<WindUser> approveUsers) {
        this.approveUsers = approveUsers;
    }

    public void setInAnd(boolean inAnd) {
        this.inAnd = inAnd;
    }

    public void setInOr(boolean inOr) {
        this.inOr = inOr;
    }

    public void setInDyna(boolean inDyna) {
        this.inDyna = inDyna;
    }

    public void build(){
        buildPaths(now);
        //构建节点指针
        createNodePointer();
    }

    public void setInterceptor(boolean interceptor) {
        this.interceptor = interceptor;
    }
}
